/*! \file logparser.cpp
    \brief This file contains implementation of class ARSARSLogFileAdapter.
    \version 1.0
*/

#include <QMessageBox>
#include <QDomDocument>
#include <QMetaProperty>

#include "admfileadapter.h"

///////// Class 'ARSLogFileAdapter' implementation ///////////////////////////////////////////////////

ADMFileAdapter::ADMFileAdapter(QObject * parent)
    : QObject(parent)
{
}

QString ADMFileAdapter::name() const
{
    return "admfileadapterplugin";
}

QString ADMFileAdapter::description() const
{
    return tr("This plugin provides \"*.adm\" files hadling. "\
              "\"*.adm\" is an XML format to store ARS log files.");
}

bool ADMFileAdapter::loadSettings()
{
    return true;
}

DynamicModel * ADMFileAdapter::createModel(QIODevice * source)
{
    QDomDocument document;
    if(!document.setContent(source))
    {
        qDebug("LogFileAdapter::xml2model: XML file corrupted");
        return 0;
    }

    ARSExecModelRootItem * rootItem = new ARSExecModelRootItem();
    DynamicModel * model = new DynamicModel(rootItem, this); /*! \todo resolve parent object */
    ARSExecItem * item = element2item(model->index(), document.firstChildElement(), rootItem);

    return model;
}

QString ADMFileAdapter::model2xml(DynamicModel * model )
{
    QDomDocument document;
    document.appendChild(item2xml(model->rootItem(), &document));
    return document.toString(4);
}

QDomElement ADMFileAdapter::item2xml( const ARSExecItem * item, QDomDocument * document )
{
    QString tagName;

    tagName = item->metaObject()->className();

    QDomElement element = document->createElement(tagName);

    const QMetaObject * itemMetaObject = item->metaObject();

    for(int i = 1; i < itemMetaObject->propertyCount(); i++)
    {
        QMetaProperty itemMetaProperty = itemMetaObject->property(i);
        QVariant propertyValue = item->property(itemMetaProperty.name());

        if(propertyValue.canConvert(QVariant::String))
            element.setAttribute(itemMetaProperty.name(), propertyValue.toString());
        else
        {
            ARSDummyObject * arsObject = ARSDummyObject::toARSObject(propertyValue);
            if(arsObject)
            {
                element.setAttribute(itemMetaProperty.name(), arsObject->name(true));
            }
            else
                element.setAttribute(itemMetaProperty.name(), QString::null);
        }
    }

    if(!item->comment().isEmpty())
        element.setAttribute("comment", item->comment());

    for(int i = 0; i < item->childCount(); i++)
    {
        element.appendChild(item2xml(item->child(i), document));
    }

    return element;
}

ARSExecItem * ADMFileAdapter::element2item( ObjectsIndex * objectsIndex, const QDomElement & element, ARSExecItem * parent )
{
    ARSExecItem * item;

    if(element.tagName() == "ARSExecModelRootItem")
        item = parent;
    else
        item = ARSExecItem::createItemByName(element.tagName(), parent);

    const QMetaObject * itemMetaObject = item->metaObject();

    for(int i = 1; i < itemMetaObject->propertyCount(); i++)
    {
        QMetaProperty itemMetaProperty = itemMetaObject->property(i);
        if(itemMetaProperty.isWritable())
        {
            QString propertyString = element.attribute(itemMetaProperty.name());
            QVariant propertyValue = string2Property(objectsIndex, propertyString, itemMetaProperty, item);
            item->setProperty(itemMetaProperty.name(), propertyValue);
        }
    }

    if(element.hasAttribute("comment"))
        item->setComment(element.attribute("comment"));

    QDomNodeList childList = element.childNodes();
    for(int i = 0; i < childList.size(); i++)
        element2item(objectsIndex, childList.at(i).toElement(), item);

    return item;
}

QVariant ADMFileAdapter::string2Property( ObjectsIndex * objectsIndex, const QString & propertyString,
                                        const QMetaProperty & itemMetaProperty, ARSExecItem * item )
{
    if(propertyString.isEmpty())
        return QVariant();

    if(itemMetaProperty.isEnumType())
        return propertyString.toInt();

    if(itemMetaProperty.type() == QVariant::String)
        return propertyString;

    if(itemMetaProperty.type() == QVariant::Int)
        return propertyString;

    if(QString(itemMetaProperty.typeName()) == "ARSDummyActiveLink*")
    {
        ARSDummyActiveLink * activeLink = objectsIndex->addActiveLink(propertyString, item);
        return QVariant::fromValue(activeLink);
    }

    if(QString(itemMetaProperty.typeName()) == "ARSDummyFilter*")
    {
        ARSDummyFilter * filter = objectsIndex->addFilter(propertyString, item);
        return QVariant::fromValue(filter);
    }

    if(QString(itemMetaProperty.typeName()) == "ARSDummyForm*")
    {
        ARSDummyForm * form = objectsIndex->addForm(propertyString, item);
        return QVariant::fromValue(form);
    }

    if(QString(itemMetaProperty.typeName()) == "ARSDummyField*")
    {
        QString formName = propertyString.split(QChar::Nbsp).first();
        ARSDummyForm * form = static_cast<ARSDummyForm *>(objectsIndex->findObject(formName, ARSObject::Form));

        if(!form)
            form = objectsIndex->addForm(formName, item);
        ARSDummyField * field = objectsIndex->addField(form, propertyString.split(QChar::Nbsp).at(1), 0, item);
        return QVariant::fromValue(field);
    }

    if(QString(itemMetaProperty.typeName()) == "ARSDummyGuide*")
    {
        QString guideTypeStr = propertyString.split(QChar::Nbsp).first();
        QString guideName = propertyString.split(QChar::Nbsp).at(1);
        ARSExecWorkflowObject::ObjectType objectsType = static_cast<ARSExecWorkflowObject::ObjectType>(guideTypeStr.toInt());
        ARSDummyGuide * guide = objectsIndex->addGuide(guideName, objectsType, item);
        return QVariant::fromValue(guide);
    }

    return QVariant();
}

ARSExecAction * ADMFileAdapter::createAction( ARSExecAction::ActionType type, ARSExecItem * parent )
{
    ARSExecAction * action = 0;

    switch(type)
    {
    case ARSExecAction::CallGuide:
        action = new ARSExecActionCallGuide(parent);
    break;
    case ARSExecAction::ChangeFields:
        action = new ARSExecActionChangeFields(parent);
    break;
    case ARSExecAction::CloseWindow:
        action = new ARSExecActionCloseWindow(parent);
    break;
    case ARSExecAction::CommitChanges:
        action = new ARSExecActionCommitChanges(parent);
    break;
    case ARSExecAction::DDE:
        action = new ARSExecActionDDE(parent);
    break;
    case ARSExecAction::DirectSQL:
        action = new ARSExecActionDirectSQL(parent);
    break;
    case ARSExecAction::DSOAction:
        action = new ARSExecActionDSOAction(parent);
    break;
    case ARSExecAction::ExitGuide:
        action = new ARSExecActionExitGuide(parent);
    break;
    case ARSExecAction::GoToGuideLabel:
        action = new ARSExecActionGoToGuideLabel(parent);
    break;
    case ARSExecAction::Goto:
        action = new ARSExecActionGoto(parent);
    break;
    case ARSExecAction::LogToFile:
        action = new ARSExecActionLogToFile(parent);
    break;
    case ARSExecAction::Message:
        action = new ARSExecActionMessage(parent);
    break;
    case ARSExecAction::Notify:
        action = new ARSExecActionNotify(parent);
    break;
    case ARSExecAction::OLEAutomation:
        action = new ARSExecActionOLEAutomation(parent);
    break;
    case ARSExecAction::OpenWindow:
        action = new ARSExecActionOpenWindow(parent);
    break;
    case ARSExecAction::RunMacro:
        action = new ARSExecActionRunMacro(parent);
    break;
    case ARSExecAction::RunProcess:
        action = new ARSExecActionRunProcess(parent);
    break;
    case ARSExecAction::Wait:
        action = new ARSExecActionWait(parent);
    break;
    case ARSExecAction::PushFields:
        action = new ARSExecActionPushFields(parent);
    break;
    case ARSExecAction::SetFields:
        action = new ARSExecActionSetFields(parent);
    break;
    }

    return action;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
